import { DesignViewModelService, DesignViewModelField, FormBindingType, DgControl, DomService, FormComponentType, FormBasicService } from '@farris/designer-services';

/**
 * 构造视图模型字段及分组树列表数据源
 */
export class FieldTreeBuilder {
  controlsInfo: any = {};
  viewModelId: string;

  constructor(
    public schemaDOMMapping: any,
    public dgVMServ: DesignViewModelService,
    public domServ: DomService,
    private formBasicServ: FormBasicService) { }

  /**
   * 构造视图模型字段及分组树列表数据源
   * @param viewModelId 视图模型标识
   */
  public buildFieldTreeData(viewModelId: string): FieldTreeNode[] {
    const dgViewModel = this.dgVMServ.getDgViewModel(viewModelId);
    if (!dgViewModel) {
      return [];
    }
    const component = this.domServ.getComponentByVMId(viewModelId);
    if (!component) {
      return [];
    }
    this.adaptOldListViewComponentType(component);
    this.viewModelId = viewModelId;
    const componentId = component.id;
    const componentType = component.componentType;
    const dgViewModelFields = dgViewModel.fields;
    if (componentType === 'dataGrid' || componentType.startsWith('form') || this.formBasicServ.envType === 'mobileDesigner') {
      const controls = this.getAllControlsInComponents(component);
      this.controlsInfo.controls = controls;
      return this.buildFieldTreeDataByControls(dgViewModelFields, controls, componentId, componentType);
    } else {
      this.controlsInfo = {};
      return this.buildFieldTreeDataByEntityFields(dgViewModelFields, componentId, componentType);
    }
  }
  /**
   * 获取指定组件实例内的所有UI控件
   * @param component 组件实例
   */
  private getAllControlsInComponents(component: any): any[] {
    const controls = [];
    const dataCollectionControl = this.getFormLayoutInCmp(component.contents);
    this.controlsInfo.formLayout = dataCollectionControl;
    if (dataCollectionControl) {
      const elementsIndataCollectionControl = dataCollectionControl.fields || dataCollectionControl.contents;
      this.getAllControlsInLayout(elementsIndataCollectionControl, controls);
    }
    return controls;
  }
  /**
   * 根据组件内控件顺序构造包含分组的视图模型字段树所需要的数据源
   * @param dgViewModelFields 视图模型字段集合
   * @param controls 视图模型对应组件内的UI控件集合
   * @param componentId 组件标识
   * @param componentType 组件类型
   */
  private buildFieldTreeDataByControls(
    dgViewModelFields: DesignViewModelField[],
    controls: any,
    componentId: string,
    componentType: string): FieldTreeNode[] {
    const treeData: FieldTreeNode[] = [];
    const groupData: Map<string, FieldTreeNode> = new Map<string, FieldTreeNode>();
    const fieldsetList = [];
    controls.forEach(control => {
      // 跳过分组节点
      if (control.type === DgControl.FieldSet.type) {
        fieldsetList.push(control);
        return;
      }
      const treeNode = this.buildFieldTreeNodeFromControl(control, dgViewModelFields, componentId, componentType);
      if (!treeNode) {
        return;
      }
      if (treeNode.isInGroupNode) {
        if (!groupData.has(treeNode.groupId)) {
          const newGroupNode = this.buildFieldTreeGroupNodeWithBindingEntityField(control, dgViewModelFields, fieldsetList);
          groupData.set(treeNode.groupId, newGroupNode);
          treeData.push(newGroupNode);
        }
        const groupNode = groupData.get(treeNode.groupId);
        groupNode.children.push(treeNode);
      } else {
        treeData.push(treeNode);
      }
    });
    return treeData;
  }
  /**
   * 构造视图模型字段树所需的数据源。
   * @param dgViewModelFields 视图模型字段集合
   * @param componentId 组件标识
   * @param componentType 组件类型
   */
  private buildFieldTreeDataByEntityFields(
    dgViewModelFields: DesignViewModelField[],
    componentId: string,
    componentType: string
  ) {
    const treeData: FieldTreeNode[] = [];
    if (dgViewModelFields && dgViewModelFields.length) {
      dgViewModelFields.forEach(viewModelField => {
        const treeNode = this.buildFieldTreeNodeFromViewModelField(viewModelField, componentId, componentType);
        if (treeNode) {
          treeData.push(treeNode);
        }
      });
    }
    return treeData;
  }

  /**
   * 适配ListView组件的类型属性：旧的模板里componentType写成了dataGrid，需要修改为ListView
   * @param component 组件实例
   */
  private adaptOldListViewComponentType(component: any) {
    if (component.componentType === 'dataGrid') {
      const dataCollectionControl = this.getFormLayoutInCmp(component.contents);
      if (dataCollectionControl.type === DgControl.ListView.type) {
        component.componentType = FormComponentType.listView;
      }
    }
  }

  /**
   * 由视图模型字段元素构造树节点
   * @param viewModelFieldElement 视图模型字段元素
   * @param componentId 组件标识
   * @param componentType 组件类型
   */
  private buildFieldTreeNodeFromViewModelField(
    viewModelFieldElement: DesignViewModelField,
    componentId: string,
    componentType: string
  ): FieldTreeNode {
    const { groupId } = viewModelFieldElement;
    const rowData = viewModelFieldElement;
    const isRemoved = viewModelFieldElement.isSchemaRemoved;
    const canChangeControlType = !viewModelFieldElement.isSchemaRemoved;
    const isComplexField = viewModelFieldElement.$type === 'ComplexField';
    const isInGroupNode = !!viewModelFieldElement.groupId;
    const fieldTreeNode = {
      canChangeControlType,
      children: [],
      componentId,
      componentType,
      control: null,
      data: rowData,
      expanded: false,
      groupId,
      isBindVariable: false,
      isComplexField,
      isGroupNode: false,
      isInGroupNode,
      isNoBinding: false,
      isRemoved,
      nodeType: 'field'
    };
    return fieldTreeNode;
  }
  /**
   * 由UI控件元素及视图模型字段集合构造树节点
   * @param control UI控件元素
   * @param dgViewModelFields 视图模型字段集合
   * @param componentId 组件标识
   * @param componentType 组件类型
   */
  private buildFieldTreeNodeFromControl(
    control: any,
    dgViewModelFields: DesignViewModelField[],
    componentId: string,
    componentType: string
  ): FieldTreeNode {
    let treeNode: FieldTreeNode;
    if (!control.binding) {
      treeNode = this.buildFieldTreeNodeWithoutControlBinding(control);
    } else if (control.binding.type === FormBindingType.Variable) {
      treeNode = this.buildFieldTreeNodeWithBindingVariable(control);
    } else {
      treeNode = this.buildFieldTreeNodeWithBindingEntityField(control, dgViewModelFields, componentId, componentType);
    }
    return treeNode;
  }
  /**
   * 构造仅有控件，没有绑定视图模型字段的节点
   * @param control UI控件元素
   */
  private buildFieldTreeNodeWithoutControlBinding(control: any): FieldTreeNode {
    const controlName = this.schemaDOMMapping.getControlName(control.type) || control.type;
    return {
      canChangeControlType: false,
      children: [],
      componentId: '',
      componentType: '',
      control,
      data: { id: control.id, name: control[controlName] },
      groupId: '',
      expanded: false,
      isBindVariable: false,
      isComplexField: false,
      isGroupNode: false,
      isInGroupNode: false,
      isNoBinding: true,
      isRemoved: false,
      nodeType: ''
    };
  }
  /**
   * 构造绑定了视图模型变量的字段节点
   * @param control UI控件元素
   */
  private buildFieldTreeNodeWithBindingVariable(control: any): FieldTreeNode {
    const controlName = this.schemaDOMMapping.getControlName(control.type) || control.type;
    const bindingFieldId = control.binding.field;
    const variable = this.domServ.getVariableById(bindingFieldId);
    const viewModelFieldElement = this.domServ.getViewModelFieldById(this.viewModelId, bindingFieldId);

    const groupId = viewModelFieldElement && viewModelFieldElement.groupId;
    return {
      canChangeControlType: false,
      children: [],
      componentId: '',
      componentType: '',
      control,
      data: {
        id: bindingFieldId,
        name: control[controlName],
        code: control.binding.fullPath || control.binding.path,
        controlType: control.type,
        type: variable && variable.type,
        category: variable && variable.category
      },
      groupId,
      expanded: false,
      isBindVariable: true,
      isComplexField: false,
      isInGroupNode: !!groupId,
      isGroupNode: false,
      isNoBinding: false,
      isRemoved: false,
      nodeType: ''
    };
  }
  /**
   * 构造绑定了视图模型字段的树节点
   * @param control UI控件元素
   * @param dgViewModelFields 视图模型字段集合
   * @param componentId 组件标识
   * @param componentType 组件类型
   */
  private buildFieldTreeNodeWithBindingEntityField(
    control: any,
    dgViewModelFields: DesignViewModelField[],
    componentId: string,
    componentType: string
  ): FieldTreeNode {
    const controlName = this.schemaDOMMapping.getControlName(control.type) || control.type;
    const bindingFieldId = control.binding.field;
    const viewModelFieldElement = dgViewModelFields.find(field => field.id === bindingFieldId);
    if (!viewModelFieldElement) {
      return null;
    }
    const { groupId, groupName } = viewModelFieldElement;
    const rowData = viewModelFieldElement.isSchemaRemoved ?
      { id: bindingFieldId, name: control[controlName] } : viewModelFieldElement;
    const isRemoved = viewModelFieldElement.isSchemaRemoved;
    const canChangeControlType = !viewModelFieldElement.isSchemaRemoved;
    const isComplexField = viewModelFieldElement.$type === 'ComplexField';
    const fieldTreeNode = {
      canChangeControlType,
      children: [],
      componentId,
      componentType,
      control,
      data: rowData,
      expanded: false,
      groupId,
      isBindVariable: false,
      isComplexField,
      isGroupNode: false,
      isInGroupNode: !!groupId,
      isNoBinding: false,
      isRemoved,
      nodeType: 'field'
    };
    return fieldTreeNode;
  }
  /**
   * 构造字段分组节点
   * @param control UI控件元素
   * @param dgViewModelFields 视图模型字段集合
   * @param fieldsetList FieldSet元素集合
   */
  private buildFieldTreeGroupNodeWithBindingEntityField(
    control: any,
    dgViewModelFields: DesignViewModelField[],
    fieldsetList: any): FieldTreeNode {
    const bindingFieldId = control.binding.field;

    // let isRemoved = false;
    // let canChangeControlType = false;
    // let isComplexField = false;
    let groupId;
    let groupName;
    if (control.binding.type === FormBindingType.Form) {
      const viewModelFieldElement = dgViewModelFields.find(field => field.id === bindingFieldId);
      if (!viewModelFieldElement) {
        return null;
      }
      // isRemoved = viewModelFieldElement.isSchemaRemoved;
      // canChangeControlType = !viewModelFieldElement.isSchemaRemoved;
      // isComplexField = viewModelFieldElement.$type === 'ComplexField';
      groupId = viewModelFieldElement.groupId;
      groupName = viewModelFieldElement.groupName;
    } else {
      const viewModelVariableElement = this.domServ.getViewModelFieldById(this.viewModelId, bindingFieldId);
      if (!viewModelVariableElement) {
        return null;
      }
      groupId = viewModelVariableElement.groupId;
      groupName = viewModelVariableElement.groupName;
    }
    const fieldSetControl = fieldsetList.find(fieldSet => fieldSet.id === groupId);
    return {
      canChangeControlType: false,
      children: [],
      componentId: '',
      componentType: '',
      control: fieldSetControl,
      data: { id: groupId, name: groupName },
      groupId,
      expanded: true,
      isBindVariable: false,
      isComplexField: false,
      isGroupNode: true,
      isInGroupNode: false,
      isNoBinding: false,
      isRemoved: false,
      nodeType: 'group'
    };
  }
  /**
   * 获取视图模型字段标识集合
   * @param viewModelId 视图模型标识
   */
  public getFieldIdList(viewModelId: string): string[] {
    const dgViewModel = this.dgVMServ.getDgViewModel(viewModelId);
    if (!dgViewModel) {
      return [];
    }
    const dgViewModelFields = dgViewModel.fields;
    const fieldIdList = dgViewModelFields.map(viewModelElementField => viewModelElementField.id);
    return fieldIdList;
  }

  /**
   * 获取组件内的基础组件父节点
   * Form、DataGrid、TreeGrid
   * @param contents  容器
   */
  getFormLayoutInCmp(contents: any[]) {
    if (!contents) {
      return {};
    }
    for (const element of contents) {
      if ((DgControl.DataGrid && DgControl.DataGrid.type === element.type) || (DgControl.TreeGrid && DgControl.TreeGrid.type === element.type) ||
        element.type === DgControl.Form.type ||
        element.type === DgControl.ListView.type) {
        return element;

      }
      if (element.contents) { // 容器组件
        const result = this.getFormLayoutInCmp(element.contents);
        if (result) {
          return result;
        }
      }

    }
    return null;
  }
  /**
   * 获取组件中绑定字段/变量的所有控件
   * @param contents 组件内容
   */
  getAllControlsInLayout(contents, controls) {
    if (!contents) {
      return;
    }
    for (const element of contents) {

      // 分组节点
      if (element.type === DgControl.FieldSet.type) {
        controls.push(element);
      }

      if (element.contents) { // 容器
        this.getAllControlsInLayout(element.contents, controls);
      } else {
        controls.push(element);
      }
    }

  }
}

/**
 * 视图模型字段及分组树列表数据源实体
 */
export interface FieldTreeNode {
  canChangeControlType: boolean;
  children: FieldTreeNode[];
  componentId: string;
  componentType: string;
  control: any;
  data: any;
  expanded: boolean;
  groupId: string;
  isBindVariable: boolean;
  isComplexField: boolean;
  isGroupNode: boolean;
  isInGroupNode: boolean;
  isNoBinding: boolean;
  isRemoved: boolean;
  nodeType: string;
}
